import {replaceByObj} from './xUtil.js';
import {hierarchyToTree,setTreeAttr,
        checkNodeByCode,expandNodeByCode,findNodeByCode,
        deleteNodeByCode,insertNode,treeFilter,getTreeLeaf,copyTree,
        expandByLevel,findAllParents,expandByNode} from './treeUtil.js';
import xID from './xID.js';
import cell from "./cell.js";

/**
 **/

const tmplBase =' <div class="{{class}}"></div>';
const tmplUl = '<ul>{{ulHtml}}</ul>';
const tmplLi =  '<li>{{cell}}{{liHtml}}</li> ';



/*
*  0 false 1 true  2 parent half checked
*  event :onSelect,onCheck,onExpand,onRender
* */

export default class xTree{
    $root;
    vTreeId =xID.getID();
    vCfg;
    $select;
    /*定义变量 结束*/
    // 构造函数
    constructor(cfg) {
        this.vCfg =cfg;
        this.$root = $('#' + cfg.el);
        this.$root.html(tmplBase.replace('{{class}}', cfg.style||'tree'));
        this.$tree = this.$root.find(">div");
        this.init();
    };

    init(){
        this.$root.on('click', '[type="tree-check"]', this.evCheck.bind(this));
        this.$root.on('click', '[type="tree-expand"]', this.evExpand.bind(this));
        this.$root.on('click', 'span[type="data"]',this.evNodeClick.bind(this));
        this.refresh();
    }

    refresh(){
        this.vCfg.data = hierarchyToTree(this.vCfg.data);
        setTreeAttr(this.vCfg.data);
        this.expandInit();
        this.renderTree();
    }

    expandInit(){
        //默认全部展开
        if(this.vCfg.expand){
            let by = this.vCfg.expand.split(' ')[0];
            let value =this.vCfg.expand.split(' ')[1];
            switch(by){
                case 'node':
                    let node = findNodeByCode(this.vCfg.data,value);
                    let parentAndSelf = findAllParents(node);
                    parentAndSelf.push(node);
                    for(let n of parentAndSelf){
                        expandByNode(n);
                    }
                    break;
                case 'level':
                    expandByLevel(this.vCfg.data,value);
                    break;
            }
        }
    }

    renderTree() {
        let _this = this;
        function renderLi(item,level){
            if((item._show==false) || (item._filter==false))
                return '';
            let html= cell.renderTree({
                //style:'nav-link '+(isActive?"active":''),
                type:'tree',
                code :item.code,
                data:item.name,
                icon:item.icon,
                image:item.image,
                _level:level,
                _check:item._check,
                _expand:item._expand,
                _virtual:item._virtual,
                badge:item.badge,
                link:item.link,
                checkable:_this.vCfg.check,
                hasChildren:item.children?true:false
            });

            return replaceByObj(tmplLi,{cell:html});
        }

        function renderUl(items,parent,level) {
            let ulHtml = '';
            for(let o of items) {
                let liHtml = '';
                liHtml += renderLi(o,level);
                //递归处理子的
                if(o.children) {
                    liHtml = liHtml.replace('{{liHtml}}', renderUl(o.children,o,level+1));
                }else
                    liHtml = liHtml.replace('{{liHtml}}','');
                ulHtml += liHtml;
            }
            return replaceByObj(tmplUl,{ulHtml});
        }
        this.$tree.html(renderUl(this.vCfg.data,null,1));
    }


    evCheck(e){
        let code = e.target.parentNode.getAttribute("data-code");
        checkNodeByCode(this.vCfg.data,code);
        this.renderTree();
        if(this.vCfg.event && this.vCfg.event.OnCheck)
            this.vCfg.event.OnCheck(findNodeByCode(this.vCfg.data,code));
    }

    /*
    * */

    evExpand(e){
        let code = e.target.parentNode.getAttribute("data-code");
        expandNodeByCode(this.vCfg.data,code);
        this.renderTree();
        if(this.vCfg.event && this.vCfg.event.OnExpand)
            this.vCfg.event.OnExpand(findNodeByCode(this.vCfg.data,code));
    }

    evNodeClick(e){
        let code = e.target.parentNode.getAttribute("data-code");
        let node = findNodeByCode(this.vCfg.data,code);
        let oldCode ;
        if(this.$select)
            oldCode = this.$select.attr("data-code")+'';
        if(this.vCfg.select  &&  oldCode!= node.code+''){
            let needActive = true;
            if(this.vCfg.onlyLeaf && node.children){
                needActive = false;
            }
            if(needActive){
                if(this.$select)
                    this.$select.removeClass('active');
                this.$select = $(e.target.parentNode);
                this.$select.addClass('active');
                if(this.vCfg.event && this.vCfg.event.OnSelect)
                    this.vCfg.event.OnSelect(node);
            }
        }
        if(this.vCfg.event && this.vCfg.event.OnNodeClick)
            this.vCfg.event.OnNodeClick(node);
    }

    setStyle(style){
        this.$root.attr('class',style);
    }

    insertNode(pCode,node){
        let result = insertNode(this.vCfg.data,pCode,node);
        if(result >0)
            this.renderTree();
        return result;
    }

    deleteNodeByCode(code){
        deleteNodeByCode(this.vCfg.data,code);
        this.renderTree();
    }

    filter(callback,value){
        treeFilter(this.vCfg.data,callback,value);
        this.renderTree();
    }

    getTreeData(){
        return this.vCfg.data;
    }

    isCheck(node){
        if(node._check>0)
            return true;
        else
            return false;
    }

    isFilter(node){
        if (!(node._filter==false))
            return true;
        else
            return false;
    }

    setData(Data){
        this.vCfg.data= Data;
        this.refresh();
    }

    getCheckLeaf(){
        return getTreeLeaf(this.vCfg.data,this.isCheck)
    }

    getCheckTree(){
        return copyTree(this.vCfg.data,this.isCheck);
    }

    getFilterLeaf(){
        return  getTreeLeaf(this.vCfg.data,this.isFilter)
    }

    getFilterTree(){
        return copyTree(this.vCfg.data,this.isFilter);
    }
}